#!/bin/bash

# 日志监控脚本 - 定期扫描日志文件并统计错误
# 使用方法: ./scripts/log-monitor.sh [--config CONFIG_FILE] [--scan] [--report] [--daemon]

set -e

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
NC='\033[0m'

# 默认配置文件
DEFAULT_CONFIG="scripts/log-monitor.conf"
# 数据存储目录
DATA_DIR="scripts/log-monitor-data"
# 报告目录
REPORT_DIR="scripts/log-monitor-reports"

# 显示帮助信息
show_help() {
    echo -e "${BLUE}📊 日志监控脚本${NC}"
    echo ""
    echo "使用方法:"
    echo "  $0 [选项]"
    echo ""
    echo "选项:"
    echo "  --config CONFIG    指定配置文件 (默认: $DEFAULT_CONFIG)"
    echo "  --scan             执行一次扫描"
    echo "  --report           生成报告"
    echo "  --daemon           启动守护进程模式"
    echo "  --help             显示此帮助信息"
    echo ""
    echo "示例:"
    echo "  $0 --scan                    # 执行一次扫描"
    echo "  $0 --report                  # 生成报告"
    echo "  $0 --daemon                  # 启动守护进程"
    echo "  $0 --config custom.conf --scan"
    echo ""
}

# 创建默认配置文件
create_default_config() {
    local config_file="$1"
    
    cat > "$config_file" << 'EOF'
# 日志监控配置文件

# 日志文件路径列表 (支持通配符)
LOG_FILES=(
    "app/logs/*.log"
    "app/logs/error.log"
    "app/logs/access.log"
    "plugins/*/logs/*.log"
)

# 错误类型定义
ERROR_TYPES=(
    "ERROR"
    "CRITICAL"
    "WARNING"
    "FATAL"
    "EXCEPTION"
    "DEPRECATED"
)

# 扫描间隔 (秒)
SCAN_INTERVAL=3600

# 报告保留天数
REPORT_RETENTION_DAYS=30

# 数据保留天数
DATA_RETENTION_DAYS=7

# 邮件通知配置 (可选)
# EMAIL_ENABLED=true
# EMAIL_TO="admin@example.com"
# EMAIL_FROM="log-monitor@example.com"
# SMTP_SERVER="smtp.example.com"
# SMTP_PORT=587
# SMTP_USER="username"
# SMTP_PASS="password"

# 钉钉/企业微信通知配置 (可选)
# WEBHOOK_URL="https://oapi.dingtalk.com/robot/send?access_token=xxx"
# WEBHOOK_SECRET="your_secret"

# 忽略的日志行模式
IGNORE_PATTERNS=(
    "DEBUG"
    "INFO"
    "health check"
    "cron job"
)
EOF

    echo -e "${GREEN}✓ 默认配置文件已创建: $config_file${NC}"
}

# 加载配置文件
load_config() {
    local config_file="$1"
    
    if [ ! -f "$config_file" ]; then
        echo -e "${YELLOW}配置文件不存在，创建默认配置...${NC}"
        create_default_config "$config_file"
    fi
    
    # 加载配置
    source "$config_file"
    
    # 设置默认值
    SCAN_INTERVAL=${SCAN_INTERVAL:-3600}
    REPORT_RETENTION_DAYS=${REPORT_RETENTION_DAYS:-30}
    DATA_RETENTION_DAYS=${DATA_RETENTION_DAYS:-7}
}

# 初始化目录
init_directories() {
    mkdir -p "$DATA_DIR"
    mkdir -p "$REPORT_DIR"
    echo -e "${GREEN}✓ 目录初始化完成${NC}"
}

# 获取日志文件列表
get_log_files() {
    local files=()
    
    for pattern in "${LOG_FILES[@]}"; do
        if [[ "$pattern" == *"*"* ]]; then
            # 处理通配符
            for file in $pattern; do
                if [ -f "$file" ]; then
                    files+=("$file")
                fi
            done
        else
            # 直接文件路径
            if [ -f "$pattern" ]; then
                files+=("$pattern")
            fi
        fi
    done
    
    echo "${files[@]}"
}

# 检查是否应该忽略某行
should_ignore_line() {
    local line="$1"
    
    for pattern in "${IGNORE_PATTERNS[@]}"; do
        if [[ "$line" == *"$pattern"* ]]; then
            return 0  # 应该忽略
        fi
    done
    
    return 1  # 不应该忽略
}

# 提取错误信息
extract_error_info() {
    local line="$1"
    local timestamp=""
    local error_type=""
    local message=""
    
    # 尝试提取时间戳 (常见格式)
    if [[ "$line" =~ ([0-9]{4}-[0-9]{2}-[0-9]{2}[[:space:]][0-9]{2}:[0-9]{2}:[0-9]{2}) ]]; then
        timestamp="${BASH_REMATCH[1]}"
    elif [[ "$line" =~ ([0-9]{2}/[0-9]{2}/[0-9]{4}[[:space:]][0-9]{2}:[0-9]{2}:[0-9]{2}) ]]; then
        timestamp="${BASH_REMATCH[1]}"
    fi
    
    # 提取错误类型
    for type in "${ERROR_TYPES[@]}"; do
        if [[ "$line" == *"$type"* ]]; then
            error_type="$type"
            break
        fi
    done
    
    # 提取错误消息 (简化版本)
    message=$(echo "$line" | sed 's/^[^:]*:[[:space:]]*//' | head -c 200)
    
    echo "$timestamp|$error_type|$message"
}

# 扫描单个日志文件
scan_log_file() {
    local log_file="$1"
    local scan_time=$(date '+%Y-%m-%d %H:%M:%S')
    local data_file="$DATA_DIR/$(basename "$log_file" .log)_$(date '+%Y%m%d').json"
    
    echo -e "${CYAN}扫描文件: $log_file${NC}"
    
    # 创建临时文件存储结果
    local temp_file=$(mktemp)
    local error_count=0
    
    # 读取日志文件并分析
    while IFS= read -r line; do
        # 检查是否应该忽略
        if should_ignore_line "$line"; then
            continue
        fi
        
        # 检查是否包含错误
        for error_type in "${ERROR_TYPES[@]}"; do
            if [[ "$line" == *"$error_type"* ]]; then
                local error_info=$(extract_error_info "$line")
                echo "$error_info" >> "$temp_file"
                ((error_count++))
                break
            fi
        done
    done < "$log_file"
    
    # 生成JSON格式的数据
    if [ $error_count -gt 0 ]; then
        echo "{" > "$data_file"
        echo "  \"log_file\": \"$log_file\"," >> "$data_file"
        echo "  \"scan_time\": \"$scan_time\"," >> "$data_file"
        echo "  \"error_count\": $error_count," >> "$data_file"
        echo "  \"errors\": [" >> "$data_file"
        
        local first=true
        while IFS= read -r error_info; do
            if [ "$first" = true ]; then
                first=false
            else
                echo "," >> "$data_file"
            fi
            
            IFS='|' read -r timestamp error_type message <<< "$error_info"
            echo "    {" >> "$data_file"
            echo "      \"timestamp\": \"$timestamp\"," >> "$data_file"
            echo "      \"type\": \"$error_type\"," >> "$data_file"
            echo "      \"message\": \"$message\"" >> "$data_file"
            echo "    }" >> "$data_file"
        done < "$temp_file"
        
        echo "  ]" >> "$data_file"
        echo "}" >> "$data_file"
        
        echo -e "${GREEN}✓ 发现 $error_count 个错误，数据已保存到 $data_file${NC}"
    else
        echo -e "${YELLOW}⚠️  未发现错误${NC}"
    fi
    
    # 清理临时文件
    rm -f "$temp_file"
}

# 执行扫描
perform_scan() {
    echo -e "${BLUE}🔍 开始扫描日志文件...${NC}"
    echo ""
    
    local log_files=($(get_log_files))
    local total_files=${#log_files[@]}
    
    if [ $total_files -eq 0 ]; then
        echo -e "${YELLOW}⚠️  未找到任何日志文件${NC}"
        return 1
    fi
    
    echo -e "${CYAN}找到 $total_files 个日志文件${NC}"
    echo ""
    
    for log_file in "${log_files[@]}"; do
        scan_log_file "$log_file"
        echo ""
    done
    
    echo -e "${GREEN}🎉 扫描完成！${NC}"
}

# 生成报告
generate_report() {
    echo -e "${BLUE}📊 生成错误报告...${NC}"
    echo ""
    
    local report_file="$REPORT_DIR/error_report_$(date '+%Y%m%d_%H%M%S').html"
    local data_files=($(find "$DATA_DIR" -name "*.json" -type f))
    
    if [ ${#data_files[@]} -eq 0 ]; then
        echo -e "${YELLOW}⚠️  没有找到任何数据文件${NC}"
        return 1
    fi
    
    # 生成HTML报告
    cat > "$report_file" << 'EOF'
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>日志错误报告</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 20px; }
        .header { background: #f0f0f0; padding: 20px; border-radius: 5px; }
        .summary { margin: 20px 0; }
        .error-type { margin: 10px 0; padding: 10px; border-left: 4px solid #ff4444; background: #fff5f5; }
        .error-item { margin: 5px 0; padding: 5px; background: #f9f9f9; border-radius: 3px; }
        .timestamp { color: #666; font-size: 0.9em; }
        .message { margin-top: 5px; }
        .stats { display: flex; gap: 20px; margin: 20px 0; }
        .stat-box { background: #e3f2fd; padding: 15px; border-radius: 5px; flex: 1; text-align: center; }
        .stat-number { font-size: 2em; font-weight: bold; color: #1976d2; }
    </style>
</head>
<body>
    <div class="header">
        <h1>📊 日志错误报告</h1>
        <p>生成时间: $(date '+%Y-%m-%d %H:%M:%S')</p>
    </div>
EOF
    
    # 统计信息
    local total_errors=0
    local error_types=()
    declare -A type_counts
    
    # 读取所有数据文件并统计
    for data_file in "${data_files[@]}"; do
        if [ -f "$data_file" ]; then
            local file_errors=$(jq -r '.error_count // 0' "$data_file" 2>/dev/null || echo "0")
            total_errors=$((total_errors + file_errors))
            
            # 统计错误类型
            while IFS= read -r error_type; do
                if [ -n "$error_type" ] && [ "$error_type" != "null" ]; then
                    if [[ ! " ${error_types[@]} " =~ " ${error_type} " ]]; then
                        error_types+=("$error_type")
                    fi
                    type_counts["$error_type"]=$((type_counts["$error_type"] + 1))
                fi
            done < <(jq -r '.errors[].type // empty' "$data_file" 2>/dev/null)
        fi
    done
    
    # 添加统计信息到报告
    echo "    <div class='summary'>" >> "$report_file"
    echo "        <h2>📈 统计概览</h2>" >> "$report_file"
    echo "        <div class='stats'>" >> "$report_file"
    echo "            <div class='stat-box'>" >> "$report_file"
    echo "                <div class='stat-number'>$total_errors</div>" >> "$report_file"
    echo "                <div>总错误数</div>" >> "$report_file"
    echo "            </div>" >> "$report_file"
    echo "            <div class='stat-box'>" >> "$report_file"
    echo "                <div class='stat-number'>${#data_files[@]}</div>" >> "$report_file"
    echo "                <div>日志文件数</div>" >> "$report_file"
    echo "            </div>" >> "$report_file"
    echo "            <div class='stat-box'>" >> "$report_file"
    echo "                <div class='stat-number'>${#error_types[@]}</div>" >> "$report_file"
    echo "                <div>错误类型数</div>" >> "$report_file"
    echo "            </div>" >> "$report_file"
    echo "        </div>" >> "$report_file"
    echo "    </div>" >> "$report_file"
    
    # 按错误类型分组显示
    for error_type in "${error_types[@]}"; do
        echo "    <div class='error-type'>" >> "$report_file"
        echo "        <h3>🚨 $error_type (${type_counts[$error_type]} 次)</h3>" >> "$report_file"
        
        # 收集该类型的所有错误
        for data_file in "${data_files[@]}"; do
            if [ -f "$data_file" ]; then
                while IFS= read -r line; do
                    if [ -n "$line" ] && [ "$line" != "null" ]; then
                        local timestamp=$(echo "$line" | jq -r '.timestamp // "未知时间"' 2>/dev/null)
                        local message=$(echo "$line" | jq -r '.message // "无消息"' 2>/dev/null)
                        local log_file=$(jq -r '.log_file // "未知文件"' "$data_file" 2>/dev/null)
                        
                        echo "        <div class='error-item'>" >> "$report_file"
                        echo "            <div class='timestamp'>📅 $timestamp | 📁 $(basename "$log_file")</div>" >> "$report_file"
                        echo "            <div class='message'>💬 $message</div>" >> "$report_file"
                        echo "        </div>" >> "$report_file"
                    fi
                done < <(jq -r --arg type "$error_type" '.errors[] | select(.type == $type) | tojson' "$data_file" 2>/dev/null)
            fi
        done
        
        echo "    </div>" >> "$report_file"
    done
    
    # 关闭HTML
    echo "</body>" >> "$report_file"
    echo "</html>" >> "$report_file"
    
    echo -e "${GREEN}✓ 报告已生成: $report_file${NC}"
    echo -e "${CYAN}总错误数: $total_errors${NC}"
    echo -e "${CYAN}错误类型: ${error_types[*]}${NC}"
}

# 清理旧数据
cleanup_old_data() {
    echo -e "${BLUE}🧹 清理旧数据...${NC}"
    
    # 清理旧报告
    find "$REPORT_DIR" -name "*.html" -mtime +$REPORT_RETENTION_DAYS -delete 2>/dev/null || true
    
    # 清理旧数据
    find "$DATA_DIR" -name "*.json" -mtime +$DATA_RETENTION_DAYS -delete 2>/dev/null || true
    
    echo -e "${GREEN}✓ 清理完成${NC}"
}

# 守护进程模式
run_daemon() {
    echo -e "${BLUE}👻 启动守护进程模式${NC}"
    echo -e "${CYAN}扫描间隔: $SCAN_INTERVAL 秒${NC}"
    echo -e "${CYAN}按 Ctrl+C 停止${NC}"
    echo ""
    
    while true; do
        perform_scan
        generate_report
        cleanup_old_data
        
        echo -e "${YELLOW}⏰ 等待 $SCAN_INTERVAL 秒后进行下次扫描...${NC}"
        sleep "$SCAN_INTERVAL"
    done
}

# 主函数
main() {
    local config_file="$DEFAULT_CONFIG"
    local action=""
    
    # 解析参数
    while [[ $# -gt 0 ]]; do
        case $1 in
            -h|--help)
                show_help
                exit 0
                ;;
            --config)
                if [[ -z "$2" || "$2" =~ ^- ]]; then
                    echo -e "${RED}错误: --config 需要指定配置文件路径${NC}"
                    exit 1
                fi
                config_file="$2"
                shift 2
                ;;
            --scan)
                action="scan"
                shift
                ;;
            --report)
                action="report"
                shift
                ;;
            --daemon)
                action="daemon"
                shift
                ;;
            -*)
                echo -e "${RED}错误: 未知参数 $1${NC}"
                show_help
                exit 1
                ;;
            *)
                echo -e "${RED}错误: 未知参数 $1${NC}"
                show_help
                exit 1
                ;;
        esac
    done
    
    echo -e "${BLUE}📊 日志监控脚本${NC}"
    echo "========================================"
    echo ""
    
    # 加载配置
    load_config "$config_file"
    
    # 初始化目录
    init_directories
    
    # 执行相应操作
    case "$action" in
        "scan")
            perform_scan
            ;;
        "report")
            generate_report
            ;;
        "daemon")
            run_daemon
            ;;
        "")
            echo -e "${YELLOW}请指定要执行的操作${NC}"
            show_help
            exit 1
            ;;
    esac
}

# 执行主函数
main "$@" 